#include <cassert>

#include "myprt.h"

// 测试对象：用于跟踪构造/析构和引用计数
struct TestObject {
    static int count;  // 跟踪对象总数
    int id;

    TestObject(int id_) : id(id_) {
        count++;
        std::cout << "TestObject(" << id << ") 构造\n";
    }

    ~TestObject() {
        count--;
        std::cout << "TestObject(" << id << ") 析构\n";
    }
};
int TestObject::count = 0;

// 测试默认构造和空指针
void test_default_construction() {
    myptr<int> p1;
    myptr<std::string> p2(nullptr);

    assert(p1.get() == nullptr);
    assert(p2.get() == nullptr);
    assert(p1.use_count() == 0);
    assert(p2.use_count() == 0);
    assert(!p1);  // 测试operator bool

    std::cout << "test_default_construction  passed\n";
}

// 测试基本构造和引用计数
void test_basic_construction() {
    // 测试原始指针构造
    myptr<TestObject> p1(new TestObject(1));
    assert(p1.use_count() == 1);
    assert(p1->id == 1);
    assert((*p1).id == 1);
    assert(TestObject::count == 1);

    // 测试拷贝构造
    myptr<TestObject> p2(p1);
    assert(p1.use_count() == 2);
    assert(p2.use_count() == 2);
    assert(p1.get() == p2.get());  // 指向同一对象
    assert(TestObject::count == 1);

    // 测试拷贝赋值
    myptr<TestObject> p3;
    p3 = p2;
    assert(p1.use_count() == 3);
    assert(p3.use_count() == 3);
    assert(TestObject::count == 1);

    // 测试自赋值
    p3 = p3;
    assert(p3.use_count() == 3);

    std::cout << "test_basic_construction  passed\n";
}

// 测试引用计数减少和对象析构
void test_destruction() {
    TestObject::count = 0;
    {
        myptr<TestObject> p1(new TestObject(2));
        {
            myptr<TestObject> p2(p1);
            {
                myptr<TestObject> p3;
                p3 = p2;
                assert(p1.use_count() == 3);
                assert(TestObject::count == 1);
            }
            assert(p1.use_count() == 2);
            assert(TestObject::count == 1);
        }
        assert(p1.use_count() == 1);
        assert(TestObject::count == 1);
    }
    // 所有指针超出作用域，对象应被析构
    assert(TestObject::count == 0);

    std::cout << "test_destruction  passed\n";
}

// 测试移动语义
void test_move_semantics() {
    TestObject::count = 0;
    myptr<TestObject> p1(new TestObject(3));
    assert(p1.use_count() == 1);

    // 测试移动构造
    myptr<TestObject> p2(std::move(p1));
    assert(p1.get() == nullptr);  // 原指针应被置空
    assert(p1.use_count() == 0);
    assert(p2.use_count() == 1);
    assert(p2->id == 3);
    assert(TestObject::count == 1);

    // 测试移动赋值
    myptr<TestObject> p3(new TestObject(4));
    myptr<TestObject> p4;
    p4 = std::move(p3);
    assert(p3.get() == nullptr);
    assert(p3.use_count() == 0);
    assert(p4.use_count() == 1);
    assert(p4->id == 4);
    assert(TestObject::count == 2);

    std::cout << "test_move_semantics  passed\n";
}

// 测试重置功能
void test_reset() {
    TestObject::count = 0;
    myptr<TestObject> p(new TestObject(5));
    assert(p.use_count() == 1);

    // 重置为新对象
    p.reset(new TestObject(6));
    assert(TestObject::count == 1);  // 旧对象应被析构
    assert(p->id == 6);
    assert(p.use_count() == 1);

    // 重置为空指针
    p.reset();
    assert(p.get() == nullptr);
    assert(p.use_count() == 0);
    assert(TestObject::count == 0);

    std::cout << "test_reset  passed\n";
}

// 测试数组支持（如果实现了）
void test_array_support() {
    // 如果myptr支持数组（如使用delete[]），取消以下注释
    /*
    myptr<int> arr(new int[5], true);  // 假设第二个参数表示数组
    for (int i = 0; i < 5; ++i) {
        arr[i] = i * 10;
    }
    assert(arr[2] == 20);
    arr.reset();  // 应调用delete[]
    
    std::cout << "test_array_support  passed\n";
    */
}

// 测试get()和swap()
void test_get_and_swap() {
    int* raw = new int(100);
    myptr<int> p1(raw);
    myptr<int> p2(new int(200));

    assert(p1.get() == raw);  // get()应返回原始指针
    assert(*p1.get() == 100);

    p1.swap(p2);
    assert(*p1 == 200);
    assert(*p2 == 100);
    assert(p1.use_count() == 1);
    assert(p2.use_count() == 1);

    std::swap(p1, p2);  // 测试std::swap
    assert(*p1 == 100);
    assert(*p2 == 200);

    std::cout << "test_get_and_swap  passed\n";
}

// 测试空悬指针和异常安全
void test_edge_cases() {
    // 测试空指针操作安全性
    myptr<int> p;
    bool caught = false;
    try {
        *p;  // 解引用空指针
    } catch (...) {
        caught = true;
    }
    assert(caught);

    // 测试不同类型指针不兼容
    myptr<int> p_int(new int(5));
    myptr<double> p_double;
    // p_double = p_int;  // 应编译错误，测试注释掉

    // 测试同一对象被多个指针管理
    //TestObject* obj = new TestObject(7);
    //myptr<TestObject> p3(obj);
    //myptr<TestObject> p4(obj);  // 危险操作（同一原始指针构造多个myptr）
    // 此时引用计数会错误（各自为1），析构时会double free
    // 此测试用于验证是否有防护（理想情况下应禁止或处理）
    std::cout << "test_edge_cases  完成（注意：同一原始指针构造多个myptr是错误用法）\n";
}

int main()
{
	test_default_construction();
	test_basic_construction();
	test_destruction();
	test_move_semantics();
	test_reset();
	test_get_and_swap();
	test_edge_cases();

	return 0;
}